#include "BindAndFunction.h"
#include "UniquePtrAndSharePtr.h"
#include "Move.h"
#include "Template.h"
#include "ConditionVariable.h"
#include "FutureAndPromise.h"

using namespace Move;
using namespace UniqueAndSharePtr;
using namespace TempLate;
using namespace ConditionVar;

static void testBindAndFunction();
static void testUniquePtrAndSharePtr();
static void testMove();
static void testTemplate();
static void testConditionVar();
static void testFutureAndPromise();

int main(void)
{

#if ( TEST_BINDANDFUNCTION == 1 )
    testBindAndFunction();
#endif

#if ( TEST_UNIQUEPTRANDSHAREPTR == 1 )
    testUniquePtrAndSharePtr();
#endif

#if ( TEST_MOVE == 1 )
    testMove();
#endif

#if ( TEST_TEMPLATE == 1 )
    testTemplate();
#endif

#if ( TEST_CONDITIONVAR == 1 )
    testConditionVar();
#endif

#if ( TEST_FUTUREANDPROMISE == 1 )
    testFutureAndPromise();
#endif

    return 0;
}


void testConditionVar()
{
    unique_ptr<ConditionVar::ConditionVariable> ptr(new ConditionVar::ConditionVariable);
    ptr->startThread();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    ptr->go();
    
    ptr->printAtomic();
}

void testTemplate()
{
    TempLate::TaskQueue<string> m_taskQueue;
    string str = "12345";
    m_taskQueue.pushQueue(str);
    std::cout << "m_taskQueue.size: " << m_taskQueue.size() << endl;

    string outStr;
    m_taskQueue.popQueue(outStr);
    std::cout << "popQueue: " << outStr << endl;
    std::cout << endl;
}

void testBindAndFunction()
{
    // 一个类调用另一个类的方法
    TestAdd ta;
    Test test;
    test.func(Add, 3,3);
    test.func(std::bind(&TestAdd::add, &ta, std::placeholders::_1, std::placeholders::_2), 8, 8);           // std::placeholders::_2 类似C语言的占位符
    std::cout << endl;

    //执行某个类的方式
    auto f = std::bind(&TestAdd::mul, &ta, std::placeholders::_1, 2);
    f(5);
    std::cout << endl;

    //判断std::function是否有效 : operator bool() 为真, 有效; 为假，无效
    std::function<void(int,int)> func_t = Add;
    if ( func_t.operator bool() )
    {
        func_t(6,6);
    }
    std::cout << endl;

}

void testUniquePtrAndSharePtr()
{
    unique_ptr<UniqueAndSharePtr::Object> ptr = nullptr;
    ptr.reset(new UniqueAndSharePtr::Object());
    ptr->add(8,8);
    std::cout << endl;

    // 释放智能指针对象，但是内存有效，返回裸指针, 如果没有其他对象接收此裸指针，会造成内存泄漏
//  ptr.release();
    unique_ptr<UniqueAndSharePtr::Object> ptr1(ptr.release());
    ptr1->add(4,4);
    std::cout << endl;

    // 禁止赋值和拷贝， 会报错
//    unique_ptr<Object> ptr2 = ptr1;
//    unique_ptr<Object> ptr3(ptr1);

    // 指针对象是栈数据时，异常报错(栈的空间随着作用域完了之后被释放，指针对象又对这块空间进行释放，导致释放无效空间，报错)
//    int num = 88;
//    unique_ptr<int> intPtr(&num);

    // 指针对象做返回值和参数
    unique_ptr<UniqueAndSharePtr::Object> uniptr = getPtr();
    std::cout << "uniptr: " << &uniptr << endl;
    std::cout << endl;

    updateInfo(std::move(uniptr), 88, string("qwert"));
    printInfo(uniptr);
    std::cout << endl;

    unique_ptr<UniqueAndSharePtr::AbsObj> ptr2(new UniqueAndSharePtr::AbsObj);
    std::cout << "ptr2: " << &ptr2 << " | get(): " << ptr2.get() << endl;
    ptr2->initVec();
    std::cout << endl;

    // std::move转成右值后可以直接进行赋值
    unique_ptr<UniqueAndSharePtr::AbsObj> ptr3(std::move(ptr2));
    std::cout << "ptr3: " << &ptr3 << " | get(): " << ptr3.get() << endl;
    std::cout << endl;

    // unique_ptr做为STL容器的元素时，不能直接进行传递，因为不可以进行拷贝和赋值操作
    vector<unique_ptr<UniqueAndSharePtr::AbsObj>> vec;
//    vec.push_back(new AbsObj);            // 错误
    vec.push_back(unique_ptr<UniqueAndSharePtr::AbsObj>(new UniqueAndSharePtr::AbsObj()));
    std::cout << "vec.size: " << vec.size() <<" | get(): " << vec.at(0).get() << endl;
    std::cout << endl;

}

void testMove()
{
    vector<Move::String> vec;
    vec.reserve(4);         //先预留空间，后面进行移动，可以节省移动构造后vec重新进行拷贝(vec空间不够时会另外申请空间，并且把数据进行拷贝)

    for ( auto i=0; i<5; i++ )
    {
        Move::String str;
        vec.push_back(std::move(str));
        std::cout << "vec.size: " << vec.size() << " |capacity: " << vec.capacity() << endl;
        std::cout << endl;
    }

    std::cout << "====================================================================" << endl;

    vector<Move::Object *> pVec;
    pVec.reserve(4);
    for ( auto i=0; i<5; i++ )
    {
        Move::Object *p = new Move::Object();
        pVec.push_back(p);
    }
    std::cout << "--pVec.size: " << pVec.size() << " |capacity: " << pVec.capacity() << endl;
    std::cout << endl;

    std::cout << "-----------------------------------------" << endl;
    std::cout << endl;

    // 拷贝构造 + 移动拷贝
    Move::Object obj(99);
    Move::Object obj1(obj);
    Move::Object obj2(std::move(obj1));
}


void testFutureAndPromise()
{
    // 声明一个promise对象, 里面存放int类型
    std::promise<int> pro;
    // 将promise和future绑定
    std::future<int> fu = pro.get_future();

    // 创建线程A， 将pro对象放到线程函数threadFuncA中执行      (std::ref传入引用参数)
    std::thread threadA(threadFuncA, std::ref(pro));
    // 创建线程B， 将fu对象放到线程函数threadFuncB中执行
    std::thread threadB(threadFuncB, std::ref(fu));
    threadA.join();
    threadB.join();

    std::cout << endl;

    // 函数指针对象作为参数时，一般使用引用类型
    std::promise<FutureAndPromise::Object> pro1;
    // 将promise和future绑定
    std::future<FutureAndPromise::Object> fu1 = pro1.get_future();

    // 创建线程C， 将pro1对象放到线程函数threadFuncC中执行      (std::ref传入引用参数)
    std::thread threadC(threadFuncC, std::ref(pro1));
    // 创建线程D， 将fu1对象放到线程函数threadFuncD中执行
    std::thread threadD(threadFuncD, std::ref(fu1));
    threadC.join();
    threadD.join();
}

